/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.google.code.biglo.dao;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.code.biglo.utils.StringToConverter;
import com.google.code.biglo.utils.StringToConverterFabric;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.orm.jpa.support.JpaDaoSupport;

public class BpmnDao extends JpaDaoSupport {

    private static final Log log = LogFactory.getLog(BpmnDao.class);

//    public OrgEntity getOrgEntity(final String name) {
//        return (OrgEntity) getJpaTemplate().execute(new JpaCallback() {
//            public Object doInJpa(EntityManager em) throws PersistenceException {
//                Query query = em.createQuery("FROM OrgEntity o WHERE o.name = :name");
//                query.setParameter("name", name);
//                return query.getSingleResult();
//            }
//        });
//    }
//    
//    /**
//     * Returns tasks presented to user based on TaskQuery criteria.
//     * @param query
//     * @return
//     */
//    @SuppressWarnings("unchecked")
//	public List<Task> getUserTasks(final TaskQuery query) {
//        
//        Validate.notNull(query);
//        
//            return (List<Task>) getJpaTemplate().executeFind(new JpaCallback() {
//                public Object doInJpa(EntityManager em) throws PersistenceException {
//                    
//                    Validate.notNull(em);
//   
//                    
//                    List<Task> tasks = buildSQLQueryForTaskQuery( query, em).setMaxResults(query.getMaxTasks()).getResultList();
//                    if(query.getWorkQueue() != null && !query.getWorkQueue().equals("")){
//                    	tasks = taskFilterByQuery(tasks, query);
//                    }
//                    return tasks;
//                }
//
//
//            });
//
//    }
//	public static  Query buildSQLQueryForTaskQuery(TaskQuery query, EntityManager em) {
////		int tan[] = new int[5];
//		Vector<Object> q= new Vector<Object>();
//		q.add("select distinct t from Task t, TaskOrgEntity e where ");//t.actualOwner = :user");
//		//q.add(new JQBParam("user", query.getUser()));
//		if(addStatuses(q, query))
//			q.add(" and ");
//		if(addOrgEntity(q, query))
//			q.add(" and ");
//		if(addGenericHumanRole(q, query))
//			q.add(" and ");
//		if(addCreatedOnClause(q, query))
//			q.add(" and ");
//		if(!addWhereClause(q, query))
//			if(q.size()>1) q.setSize(q.size()-1);
//		q.add(" order by t.id");
//		
//		return new JpaQueryBuilder().buildQuery(em, q.toArray());	
//	}
//    
//	private static boolean addOrgEntity(Vector<Object> q, TaskQuery query){
//		if(query.getGenericHumanRole() != null && query.getGenericHumanRole().equals(GenericHumanRole.ACTUALOWNER)){
//			return false;
//		}
//
//		//solution without permissions. Searches are all tasks within the group.
//		if(query.getWorkQueue() == null || query.getWorkQueue().equals("")){
//			q.add(" e.task = t and (e.name = :user and e.type = :constUser");
//			q.add(new JQBParam("user", query.getUser()));
//			q.add(new JQBParam("constUser", TaskOrgEntity.OrgEntityType.USER));
//			q.add( new JQBParam("groups", query.getUserGroups(), 
//				new Object[] {
//                	" or e.name in (:groups) and e.type = :constGroup", 
//                	new JQBParam("constGroup", TaskOrgEntity.OrgEntityType.GROUP)
//            	}));
//		}else{
//				//if workQueue is defined
//			q.add(" e.task = t and (e.name = :workQueue and e.type = :constUser");
//			q.add(new JQBParam("workQueue", query.getWorkQueue()));
//			q.add(new JQBParam("constUser", TaskOrgEntity.OrgEntityType.GROUP));
//		}	
//		q.add(") ");
//		return true;
//		
//	}
//	
//	private static boolean addWhereClause(Vector<Object> q, TaskQuery query) {
//		String clause=query.getWhereClause();
//    	if(clause==null) return false;
//    	return (createWhereClause(q, clause, "addition"));
//    	
//	}
//
//	private static boolean addGenericHumanRole(Vector<Object> q, TaskQuery query){
//        if(query.getGenericHumanRole()==null) return false;
//        switch (query.getGenericHumanRole()) {
//        case ACTUALOWNER:
//        	if(query.getWorkQueue() == null || query.getWorkQueue().equals("")){
//        			q.add(" t.actualOwner = :user");
//        			q.add(new JQBParam("user", query.getUser()));
//        	}else{
//        			q.add(" t.actualOwner = :workQueue");
//        			q.add(new JQBParam("workQueue", query.getWorkQueue()));
//        	}
//        	return true;
//        case POTENTIALOWNERS:
//        case BUSINESSADMINISTRATORS:
//        case EXCLUDEDOWNERS:
//        case TASKSTAKEHOLDERS:
//                     q.add("e.genericHumanRole = :role");
//                     q.add(new JQBParam("role", query.getGenericHumanRole()));
//                     return true;
//                            
//        default:
//            throw new IllegalStateException("generic human role not supported");
//        }
//	}
//	
//	private static boolean createWhereClause(Vector<Object> q, String clause, String name){
//    	StringTokenizer st = new StringTokenizer(clause, "<>=", true);
//    	Vector<String> tokens=new Vector<String>();
//    	String operands=new String("");
//    	String value=new String("");
//    	if(st.countTokens()<3) return false;
//    	String entity=st.nextToken();
//    	while(st.hasMoreTokens()){
//    			String token=st.nextToken();
//    			if(st.hasMoreTokens()) operands+=token;
//    			else value=token;
//    	}
//    	
//    	StringToConverter conv=StringToConverterFabric.createConverter(value);
//		Object temp=conv.convert(value);
//		
//		q.add(new JQBParam(name, temp,
//					new Object[] {
//            			" t."+entity+" "+operands+" :"+name, 
//        			})
//		);
//		return true;
//		
//	}
//	
//    private static boolean addCreatedOnClause(Vector<Object> q, TaskQuery query) {
//    	if(query.getCreatedOnClause()==null)
//    		return false;
//    	String clause = new String("createdOn"+query.getCreatedOnClause());
//    	return createWhereClause(q, clause, "createdOn");
//    	
//	}
//	
//	
//    private static boolean addStatuses(Vector<Object> q, TaskQuery query) {
//    	if(!query.getStatuses().isEmpty()){
//    		q.add(" ( ");
//    		for(int i=0; i<query.getStatuses().size(); ++i){
//    			q.add(new JQBParam("status"+i, Task.Status.fromValue(query.getStatuses().get(i).toString()),
//    					new Object[] {
//                			" t.status = :status"+i, 
//            			})
//    			);
//    			if(i<query.getStatuses().size()-1) q.add(" or ");
//    			
//    		}
//    		q.add(" ) ");
//    		return true;
//    	}
//    	return false;
//		
//	}
//
//	public List<Job> listJobs(final Date until, final int maxResult) {
//        return (List<Job>) getJpaTemplate().executeFind(new JpaCallback() {
//            public Object doInJpa(EntityManager em) throws PersistenceException {
//                return em.createQuery("select j from Job j where j.fire < :until order by j.fire")
//                .setParameter("until", until)
//                .setMaxResults(maxResult)
//                .getResultList();
//            }
//        });
//    }
//
    public <T> T find(Class<T> what, Object id) {
        return getJpaTemplate().find(what, id);
    }
    
    public void remove(Object o) {
        getJpaTemplate().remove(o);
        getJpaTemplate().flush();
    }

    public void persist(Object o) {
        getJpaTemplate().persist(o);
        getJpaTemplate().flush();
    }
    
    public <T> void clearAllRecords(Class<T> clazz) {
        log.debug("select t from " + clazz.getName());
        for (Object o : getJpaTemplate().find("select t from " + clazz.getName() + " t")) {
            getJpaTemplate().remove(o);
        }
    }
    
//	public<T> List find(final String query, final List parameters,  final Class<T> what){
//		
//		JpaTemplate jpaTemp=getJpaTemplate();
//		Object result=jpaTemp.execute(new JpaCallback() {					
//				public Object doInJpa(EntityManager em) throws PersistenceException {
//					//String temp1;
//					
//					Query q=em.createNativeQuery(query, what);
//					for(int i=0; i<parameters.size();++i){
//						//temp1=parameters.get(i);
//						q.setParameter(i+1, parameters.get(i));
//					}
//					List res=q.getResultList();					
//					
//        
//               	
//					return res;
//					
//				}
//			});
//		
//		return (List)result;
//	
//	}
//	
//	private List<Task> taskFilterByQuery(List<Task> tasks, TaskQuery query){
//    	query.setWorkQueue(null);
//    	query.setGenericHumanRole(null);
//    	List<com.google.code.biglo.dao.Task> taskWithPossibleAccess = getUserTasks(query);
//    	List<com.google.code.biglo.dao.Task> filteredTasks = new ArrayList<com.google.code.biglo.dao.Task>();
//    	
//    	for(com.google.code.biglo.dao.Task i : tasks){
//    		if(taskWithPossibleAccess.contains(i)){
//    			filteredTasks.add(i);
//    		}
//    	}
//    	return filteredTasks;
//    }

    public List<ActivityDao> findActivityToExecute(final Long instanceId) {
      return (List<ActivityDao>) getJpaTemplate().executeFind(new JpaCallback() {
	      public Object doInJpa(EntityManager em) throws PersistenceException {
	          return em.createQuery("select a from ActivityDao a where a.instance = :id and a.state in (:enabled, :completing)")
	          .setParameter("id", instanceId)
	          .setParameter("enabled", ActivityState.ENABLED)
	          .setParameter("completing", ActivityState.COMPLETING)
	          .setMaxResults(1)
	          .getResultList();
	      }
	  });
    }
    
    public Long countActivitiesToExecuteInScope(final Long instanceId, final Long parentId) {
        return (Long) getJpaTemplate().execute(new JpaCallback() {
  	      public Object doInJpa(EntityManager em) throws PersistenceException {
  	    	  if (parentId == null) {
	  	          return em.createQuery("select count(a) from ActivityDao a where a.instance = :id and a.parent is null and a.state in (:enabled, :completing)")
	  	          .setParameter("id", instanceId)
		          .setParameter("enabled", ActivityState.ENABLED)
		          .setParameter("completing", ActivityState.COMPLETING)
	  	          .getSingleResult();
  	    	  } else {
	  	          return em.createQuery("select count(a) from ActivityDao a where a.instance = :id and a.parent = :parentId and a.state in (:enabled, :completing)")
	  	          .setParameter("id", instanceId)
	  	          .setParameter("parentId", parentId)
		          .setParameter("enabled", ActivityState.ENABLED)
		          .setParameter("completing", ActivityState.COMPLETING)
	  	          .getSingleResult();
  	    	  }
  	      }
  	  });
    }
}
